/*
 * This file is part of quickReminder, a software for gamers
 *
 * Copyright (C) 2006-2008 Lucas Romero
 *
 * This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along with this program; if not, see <http://www.gnu.org/licenses/>.
 */
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Imaging;
using System.Text;
using System.Windows.Forms;
using System.Net;
using HtmlAgilityPack;
using System.Diagnostics;
using System.IO;
using System.Collections.Specialized;
using System.Text.RegularExpressions;

namespace quickReminder
{
    public partial class FormChallengeSetup : Form
    {
        public FormChallengeSetup()
        {
            InitializeComponent();
            cmbLeague.SelectedIndexChanged += new EventHandler(cmbLeague_SelectedIndexChanged);

            ParseLeagues();
            //SetupFields();
        }

        private string m_Challenge;

        public string Challenge
        {
            get { return m_Challenge; }
            set { m_Challenge = value; }
        }

        void cmbLeague_SelectedIndexChanged(object sender, EventArgs e)
        {
            SetupFields(cmbLeague.SelectedItem.Link);
            //bStart.Enabled = true;
        }

        ImageList flags = new ImageList();

        public void ParseLeagues()
        {
            string HTML = GetHTML(@"http://www.esl.eu/instantchallenge/", Settings.Default.Cookie);
            HtmlAgilityPack.HtmlDocument d = new HtmlAgilityPack.HtmlDocument();
            d.LoadHtml(HTML);

            HtmlNodeCollection leagues = d.DocumentNode.SelectNodes(@"//div[text()=""Select the desired league:""]/a");
            if (leagues != null)
            {
                foreach(HtmlNode n in leagues)
                {
                    string img = n.SelectSingleNode("img").Attributes["src"].Value;
                    string name = n.InnerText.Trim();
                    Image curimg;
                    if (flags.Images[Path.GetFileName(img)] == null)
                        curimg = GetImage(img);
                    else
                        curimg = flags.Images[Path.GetFileName(img)];
                    cmbLeague.Add(new LeagueItem(name, n.Attributes["href"].Value, curimg));
                }
                cmbLeague.Enabled = true;
            }

            //d.LoadHtml(HTML);
        }

        public Image GetImage(string url)
        {
            WebClient c = new WebClient();
            Image img = null;
            try
            {
                using (Stream s = c.OpenRead(url))
                {
                    img = Image.FromStream(s);
                }
            }
            catch (WebException)
            {
            }
            return img;
        }

        private StringDictionary LoadParameters(string league)
        {
            StringDictionary d = new StringDictionary();
            try
            {
                using (StreamReader w = new StreamReader(Path.Combine(GlobalSettings.RuntimeSettings.SettingsDir, league.Replace('/', '.') + "conf")))
                {
                    foreach (Match m in Regex.Matches(w.ReadToEnd(), @"^(.*?)=(.*?)\r*$", RegexOptions.Multiline))
                        d.Add(m.Groups[1].Value, m.Groups[2].Value);
                }
            }
            catch(IOException)
            { }
            return d;
        }

        private void SetupFields(string url)
        {
            tabSetup.Controls.Clear();

            StringDictionary settings = LoadParameters(url);

            string HTML = GetHTML(url, Settings.Default.Cookie);
            HtmlAgilityPack.HtmlDocument d = new HtmlAgilityPack.HtmlDocument();
            HtmlNode.ElementsFlags.Remove("form");
            HtmlNode.ElementsFlags.Remove("option");
            //HtmlNode.ElementsFlags["input"] = HtmlElementFlag.CanOverlap;
            d.LoadHtml(HTML);

            if (d.DocumentNode.SelectSingleNode(@"//h2[text()=""ESL Instant Challenger""]/../table[not(@id)]//div[text()=""Session exists""]") != null)
            {
                Debug.WriteLine("Active search existed, deleting...");
                HTML = GetHTML(url + "deletesession/", Settings.Default.Cookie);
                d.LoadHtml(HTML);
            }

            if (string.IsNullOrEmpty(HTML) || d.DocumentNode.SelectSingleNode(@"//div[text()=""The Instant Challenger currently not active in this League. Please check the times at which it is available.""]") != null)
            {
                //xpath for activation date: @"//div[text()=""The Instant Challenger currently not active in this League. Please check the times at which it is available.""]/following-sibling::div/text()"
                lInactive.Visible = true;
                bStart.Enabled = false;
                return;
            }
            else
            {
                lInactive.Visible = false;
                bStart.Enabled = true;
            }



            string opts = @"//form[@method=""post""]//input[@type!=""submit""] | //form[@method=""post""]//select";
            //string opts = @"//form[@method=""post""]/../table[@id=""table_options""]//input | //form[@method=""post""]/../table[@id=""table_options""]//select | //form[@method=""post""]/../table[not(@id)]//select | //form[@method=""post""]/../table[not(@id)]//input";
            HtmlNodeCollection parameters = d.DocumentNode.SelectNodes(opts);
            StringCollection radios = new StringCollection();

            if (parameters != null)
            {
                foreach (HtmlNode n in parameters)
                {
                    if (n.Attributes["type"] != null && n.Attributes["type"].Value == "hidden")
                        continue;
                    if (n.NodeType != HtmlNodeType.Element)
                        continue;
                    Label title = new Label();
                    title.TextAlign = ContentAlignment.MiddleLeft;
                    title.Dock = DockStyle.Fill;
                    Control setting = null;
                    if (n.SelectSingleNode("../../td[1]") == null)
                        continue;
                    title.Text = n.SelectSingleNode("../../td[1]").InnerText;
                    if (n.Name.ToLower() == "select")
                    {
                        
                        ComboBox cmb = new ComboBox();
                        cmb.Tag = new HtmlFormElement(n.Attributes["name"].Value, string.Empty, HtmlFormElement.HtmlFormElementType.ComboBox);
                        cmb.DropDownStyle = ComboBoxStyle.DropDownList;
                        cmb.Width = 200;
                        //cmb.DropDownWidth = 200;
                        setting = cmb;
                        foreach (HtmlNode n2 in n.SelectNodes("option"))
                        {
                            cmb.Items.Add(new HtmlComboBoxElement(n2.InnerText, n2.Attributes["value"].Value));
                            if (n2.Attributes["selected"] != null)
                                cmb.SelectedIndex = cmb.Items.Count - 1;
                        }
                        if (cmb.SelectedIndex < 0)
                            cmb.SelectedIndex = 0;
                        if (settings.ContainsKey(n.Attributes["name"].Value))
                            foreach (HtmlComboBoxElement i in cmb.Items)
                                if (i.Value == settings[n.Attributes["name"].Value])
                                    cmb.SelectedItem = i;
                    }
                    else if (n.Name.ToLower() == "input")
                    {
                        if (n.Attributes["type"] != null && n.Attributes["type"].Value.ToLower() == "checkbox")
                        {
                            //is a checkbox
                            CheckBox cb = new CheckBox();
                            cb.Dock = DockStyle.Fill;
                            cb.TextAlign = ContentAlignment.MiddleLeft;
                            cb.CheckAlign = ContentAlignment.MiddleLeft;
                            cb.Tag = new HtmlFormElement(n.Attributes["name"].Value, n.Attributes["value"].Value, HtmlFormElement.HtmlFormElementType.CheckBox);
                            setting = cb;
                            cb.Text = n.ParentNode.InnerText.Trim();
                            if (settings.ContainsKey(n.Attributes["name"].Value))
                                cb.Checked = true;
                        }
                        else if (n.Attributes["type"] != null && n.Attributes["type"].Value.ToLower() == "radio")
                        {
                            if (!radios.Contains(n.Attributes["name"].Value.ToLower()))
                            {
                                radios.Add(n.Attributes["name"].Value.ToLower());
                                ComboBox cmb = new ComboBox();
                                /*int size = 100;
                                if (n.Attributes["size"] != null)
                                    if (Int32.TryParse(n.Attributes["size"].Value, out size))
                                        size = size * 2;*/
                                cmb.Width = 200;
                                //cmb.DropDownWidth = 200;
                                cmb.DropDownStyle = ComboBoxStyle.DropDownList;
                                cmb.Tag = new HtmlFormElement(n.Attributes["name"].Value, string.Empty, HtmlFormElement.HtmlFormElementType.CheckBox);
                                setting = cmb;

                                foreach (HtmlNode n2 in n.ParentNode.SelectNodes(@"input[@type=""radio""]"))
                                {
                                    cmb.Items.Add(new HtmlComboBoxElement(n2.NextSibling.InnerText.Trim(), n2.Attributes["value"].Value));
                                    if (n2.Attributes["selected"] != null)
                                        cmb.SelectedIndex = cmb.Items.Count - 1;
                                }
                                if (cmb.SelectedIndex < 0)
                                    cmb.SelectedIndex = 0;
                                if (settings.ContainsKey(n.Attributes["name"].Value))
                                    foreach (HtmlComboBoxElement i in cmb.Items)
                                        if (i.Value == settings[n.Attributes["name"].Value])
                                            cmb.SelectedItem = i;
                            }
                        }
                        else
                        {
                            TextBox txt = new TextBox();
                            txt.Tag = n.Attributes["name"].Value;
                            txt.Width = 200;
                            setting = txt;
                            if (n.Attributes["value"] != null)
                                txt.Text = n.Attributes["value"].Value;
                            if (settings.ContainsKey(n.Attributes["name"].Value))
                                txt.Text = settings[n.Attributes["name"].Value];
                        }
                    }
                    if (setting != null)
                    {
                        tabSetup.Controls.Add(title);
                        tabSetup.Controls.Add(setting);
                    }
                }
            }
            
            tabSetup.Controls.Add(new Panel());
        }

        public string GetHTML(string URL, string cook)
        {
            return GetHTML(URL, new Cookie("COOKIE", cook, "/", ".esl.eu"));
        }
        public string GetHTML(string URL, Cookie cook)
        {
            URL = URL.Replace("&amp;", "&");
            if (!URL.StartsWith("http://www.esl.eu"))
                URL = "http://www.esl.eu" + URL;
            Debug.WriteLine("HTTP GET: " + URL);
            string HTML = String.Empty;
            HttpWebRequest request;
            HttpWebResponse response;
            StreamReader answer = null;
            request = (HttpWebRequest)WebRequest.Create(URL);
            request.Timeout = 10000;
            request.CookieContainer = new CookieContainer();
            request.CookieContainer.Add(cook);
            //get response

            try
            {
                response = (HttpWebResponse)request.GetResponse();
                answer = new StreamReader(response.GetResponseStream(), System.Text.Encoding.UTF8);
                //while (m_UploadStatus != ItemUploadStatus.Aborted && answer.ReadLine() != String.Empty)
                //{
                //HTML += answer.ReadLine();
                //}
                HTML = answer.ReadToEnd();
            }
            catch (Exception)
            {
                return string.Empty;
            }
            finally
            {
                if (answer != null)
                    answer.Close();
            }
            return HTML;
        }

        private void bStart_Click(object sender, EventArgs e)
        {
            StringBuilder challenge = new StringBuilder(((LeagueItem)cmbLeague.SelectedItem).Link + "start/?");
            StringCollection args = new StringCollection();
            /*for(int i=0; i<tabSetup.RowCount; i++)
            {
                Control c = tabSetup.GetControlFromPosition(1,i);
                if (c != null)
                {*/
            StringCollection settings = new StringCollection();
            foreach(Control c in tabSetup.Controls)
            {
                    if (c is ComboBox)
                    {
                        ComboBox cmb = c as ComboBox;
                        HtmlFormElement elem = cmb.Tag as HtmlFormElement;
                        HtmlComboBoxElement selected = cmb.SelectedItem as HtmlComboBoxElement;
                        challenge.Append(elem.Name + "=" + selected.Value + "&");
                        settings.Add(elem.Name + "=" + selected.Value);
                        //args.Add(elem.Name + "=" + selected.Value);
                    }
                    else if(c is TextBox)
                    {
                        TextBox txt = c as TextBox;
                        challenge.Append((string)txt.Tag + "=" + txt.Text + "&");
                        settings.Add((string)txt.Tag + "=" + txt.Text);
                        //args.Add((string)txt.Tag + "=" + txt.Text);
                    }
                    else if (c is CheckBox)
                    {
                        CheckBox cb = c as CheckBox;
                        HtmlFormElement elem = cb.Tag as HtmlFormElement;
                        if (cb.Checked)
                        {
                            //args.Add(elem.Name + "=" + elem.Value);
                            challenge.Append(elem.Name + "=" + elem.Value + "&");
                            settings.Add(elem.Name + "=" + elem.Value);
                        }
                    }
            }
            m_Challenge = challenge.ToString();
            SaveParameters(((LeagueItem)cmbLeague.SelectedItem).Link, settings);
            //MessageBox.Show(challenge);
        }

        private void SaveParameters(string url, StringCollection settings)
        {
            using (StreamWriter w = new StreamWriter(Path.Combine(GlobalSettings.RuntimeSettings.SettingsDir, url.Replace('/','.') + "conf")))
            {
                foreach (string s in settings)
                    w.WriteLine(s);
            }
        }
    }


    public class HtmlComboBoxElement
    {
        string m_Text;
        string m_Value;
        public string Value
        {
            get { return m_Value; }
            set { m_Value = value; }
        }
        public HtmlComboBoxElement(string text, string value)
        {
            m_Text = text;
            m_Value = value;
        }
        public override string ToString()
        {
            return m_Text;
        }
    };

    public class HtmlFormElement
    {
        string m_Name;
        public string Name
        {
            get { return m_Name; }
            set { m_Name = value; }
        }
        string m_Value;
        public string Value
        {
            get { return m_Value; }
            set { m_Value = value; }
        }
        HtmlFormElementType m_Type;
        public HtmlFormElementType Type
        {
            get { return m_Type; }
            set { m_Type = value; }
        }

        public HtmlFormElement(string name, string value, HtmlFormElementType type)
        {
            m_Name = name;
            m_Value = value;
            m_Type = type;
        }

        public enum HtmlFormElementType
        {
            Text,
            ComboBox,
            CheckBox,
        };
    };

    public class LeagueItem : ImageComboBox<LeagueItem>.IImgComboBoxItem
    {
        Image m_Image;
        string m_Text;

        public string Text
        {
            get { return m_Text; }
            set { m_Text = value; }
        }
        string m_Link;

        public string Link
        {
            get { return m_Link; }
            set { m_Link = value; }
        }
        public Image GetImage()
        {
            return m_Image;
        }

        public override string ToString()
        {
            return m_Text;
        }

        public LeagueItem(string text, string link, Image img)
        {
            m_Text = text;
            m_Link = link;
            m_Image = img;
        }
    }

    public class LeagueSelectBox : ImageComboBox<LeagueItem>
    {
        public LeagueSelectBox() : base()
        {
            
        }
    };

    public class ImageComboBox<T> : ComboBox
        //T can be any type, but that type MUST implement the IImgComboBoxItem interface
        where T : ImageComboBox<T>.IImgComboBoxItem
    {
        public interface IImgComboBoxItem
        {
            Image GetImage();
        }
        //clip text so no incomplete lines will be drawn
        private StringFormat m_Format = new StringFormat(StringFormatFlags.LineLimit);
        private int m_Spacing = 3;
        private Size m_ImageSize = new Size(16, 16);
        private bool m_FillImageBackground;

        #region Properties
        public bool FillImageBackground
        {
            get { return m_FillImageBackground; }
            set { m_FillImageBackground = value; }
        }
        private string m_TextEmpty;

        [Browsable(true)]
        [Localizable(true)]
        public string TextEmpty
        {
            get { return m_TextEmpty; }
            set { m_TextEmpty = value; }
        }


        //hide "DropDownStyle" Attribute and make it readonly because we want to lock it to ComboBoxStyle.DropDownList
        [Browsable(false)]
        public new ComboBoxStyle DropDownStyle
        {
            get
            {
                return base.DropDownStyle;
            }
            set
            {
                //ignore
            }
        }

        public Size ImageSize
        {
            get { return m_ImageSize; }
            set { m_ImageSize = value; }
        }

        public int Spacing
        {
            get { return m_Spacing; }
            set { m_Spacing = value; }
        }

        public StringAlignment VAlign
        {
            get
            {
                return m_Format.Alignment;
            }
            set
            {
                m_Format.Alignment = value;
            }
        }

        public StringAlignment HAlign
        {
            get
            {
                return m_Format.LineAlignment;
            }
            set
            {
                m_Format.LineAlignment = value;
            }
        }
        #endregion

        public ImageComboBox()
        {
            base.DropDownStyle = ComboBoxStyle.DropDownList;
            //set control to ownerdrawn so we can paint our items ourselves
            this.DrawMode = DrawMode.OwnerDrawFixed;
            //left-align text by default
            m_Format.Alignment = StringAlignment.Near;
            m_Format.LineAlignment = StringAlignment.Center;
            //trim text if it does not fit inside our item's bounds and draw "..." after the cut-off text
            m_Format.Trimming = StringTrimming.EllipsisCharacter;
            //adjust ItemHeight if necessary (ImageSize > ItemHeight)
            ItemHeight = Math.Max(ItemHeight, m_ImageSize.Height);
        }

        public void Add(T item)
        {
            Items.Add(item);
        }

        //"new" tells the compiler we want to "hide" the inherited property "SelectedItem" and replace it by our customized one
        public new T SelectedItem
        {
            get
            {
                return (T)base.SelectedItem;
            }
            set
            {
                base.SelectedItem = value;
            }
        }

        protected override void OnDrawItem(DrawItemEventArgs e)
        {
            //draw background and focus rectangle
            e.DrawBackground();
            e.DrawFocusRectangle();

            //paint an "empty" item (read: don't paint)
            if (e.Index < 0)
            {
                e.Graphics.DrawString(TextEmpty, e.Font, new SolidBrush(e.ForeColor), e.Bounds, m_Format);
                return;
            }

            //get the object associated with the item
            T item = (T)this.Items[e.Index];
            //get image belonging to item
            Image icon = item.GetImage();

            //center Image
            int boundTop = e.Bounds.Top + (int)Math.Round(((this.ItemHeight - icon.Height) / 2.0));
            //create the two rectangles we will be painting to
            Rectangle imgrect = new Rectangle(e.Bounds.Left, boundTop, m_ImageSize.Width, m_ImageSize.Height);
            Rectangle textrect = new Rectangle(imgrect.Right + m_Spacing, e.Bounds.Top, e.Bounds.Width - (imgrect.Width + m_Spacing), e.Bounds.Height);

            //optionally: paint white background before painting image
            if (m_FillImageBackground)
                e.Graphics.FillRectangle(new SolidBrush(BackColor), imgrect);

            //variable to determine boundary unit
            //GraphicsUnit gunit = GraphicsUnit.Pixel;


            //draw whole image image (specified by GetBounds()) and eventually resize it to fit inside the imgrect
            e.Graphics.DrawImageUnscaled(icon, imgrect);
            //e.Graphics.DrawImage(icon, imgrect, icon.GetBounds(ref gunit), gunit);
            //draw formatted string
            e.Graphics.DrawString(item.ToString(), e.Font, new SolidBrush(e.ForeColor), textrect, m_Format);
        }
    }
}